"use strict";

const SIGNAL_TYPE_JOIN = "join"; //加入房间
const SIGNAL_TYPE_RESP_JOIN = "resp_join"; //告知加入者是谁，发送给加入的人
const SIGNAL_TYPE_LEAVE = "leave"; //离开房间
const SIGNAL_TYPE_NEW_PEER = "new_peer"; //新加入者，发送给在房间的人
const SIGNAL_TYPE_PEER_LEAVE = "peer_leave"; //告知离开者是谁
const SIGNAL_TYPE_OFFER = "offer"; //发送offer
const SIGNAL_TYPE_ANSWER = "answer"; //对端回复
const SIGNAL_TYPE_CANDIDATE = "candidate"; //发送candidate

var localVideo = document.querySelector("#localVideo");
var remoteVideo = document.querySelector("#remoteVideo");
var localStream = null;
var remoteStream = null;

var rtcEngine = null;

var localUserId = Math.random().toString(36).substring(2); //生成本地id
var remoteUserId = -1; //对端id
var roomId = 0; //房间号

var pc = null; //RTCPeerConnection对象

var isInRoom = false;

//相当于构造函数
var RTCEngine = function (wsUrl) {
    //传入的函数形参
    this.init(wsUrl); //init相当于成员函数
    rtcEngine = this;
    return this; //返回自身实例
};

//初始化RTCEngine
RTCEngine.prototype.init = function (wsUrl) {
    this.wsUrl = wsUrl; //wsUrl是成员变量
    this.signaling = null; //websocket对象
};

//创建WebSocket连接
RTCEngine.prototype.createWebSocket = function () {
    rtcEngine = this;
    rtcEngine.signaling = new WebSocket(this.wsUrl);

    //绑定WebSocket回调函数
    rtcEngine.signaling.onopen = function () {
        rtcEngine.onOpen();
    };
    rtcEngine.signaling.onmessage = function (event) {
        rtcEngine.onMessage(event);
    };
    rtcEngine.signaling.onerror = function (event) {
        rtcEngine.onError(event);
    };
    rtcEngine.signaling.onclose = function (event) {
        rtcEngine.onClose(event);
    };
};

//向WebSocket服务器发送消息
RTCEngine.prototype.sendMessage = function (message) {
    rtcEngine.signaling.send(message);
};

//WebSocket连接成功回调函数，RTCEngine的成员函数
RTCEngine.prototype.onOpen = function () {
    console.log("WebSocket连接成功");
};

//WebSocket连接失败回调函数，RTCEngine的成员函数
RTCEngine.prototype.onError = function (event) {
    console.log("WebSocket连接失败:" + event.data);
};

//WebSocket连接关闭回调函数，RTCEngine的成员函数
RTCEngine.prototype.onClose = function (event) {
    console.log("WebSocket连接关闭:" + event.data);
    isInRoom = false;
};

//WebSocket接收消息回调函数，RTCEngine的成员函数
RTCEngine.prototype.onMessage = function (event) {
    console.log("WebSocket接收消息:" + event.data);

    //解析消息：JSON格式
    var msg = JSON.parse(event.data);
    console.log("解析后的JSON消息:", msg);
    switch (msg.cmd) {
        case SIGNAL_TYPE_NEW_PEER: //新加入者
            handleRemoteNewPeer(msg);
            break;
        case SIGNAL_TYPE_RESP_JOIN: //加入者回复
            handleResponseJoin(msg);
            break;
        case SIGNAL_TYPE_PEER_LEAVE: //离开者
            handleRemotePeerLeave(msg);
            break;
        case SIGNAL_TYPE_OFFER: //收到offer
            handleRemoteOffer(msg);
            break;
        case SIGNAL_TYPE_ANSWER: //收到answer
            handleRemoteAnswer(msg);
            break;
        case SIGNAL_TYPE_CANDIDATE: //收到candidate
            handleRemoteCandidate(msg);
            break;
    }
};

//有人加入，发送给房间的人
function handleRemoteNewPeer(msg) {
    console.log("房间里面的人：" + msg.remoteUid);
    remoteUserId = msg.remoteUid;
    doOffer();
}

//有人加入，发送给加入者
function handleResponseJoin(msg) {
    console.log("加入者：" + msg.remoteUid);
    remoteUserId = msg.remoteUid;
}

//有人离开，发送给房间的人
function handleRemotePeerLeave(msg) {
    console.log("离开者：" + msg.remoteUid);
    remoteVideo.srcObject = null;
    remoteUserId = -1;
    if (pc != null) {
        pc.close();
        pc = null;
    }
}

//收到offer,创建PeerConnection对象,保存sdp，并且回复answer
function handleRemoteOffer(msg) {
    console.log("收到offer");
    if (pc == null) {
        createPeerConnection();
    }

    var desc = JSON.parse(msg.message);
    pc.setRemoteDescription(desc); //设置对端sdp

    doAnswer(); //回复answer
}

//收到answer,保存sdp
function handleRemoteAnswer(msg) {
    console.log("收到answer");
    var desc = JSON.parse(msg.message);
    pc.setRemoteDescription(desc); //设置对端sdp
}

//处理candidate
function handleRemoteCandidate(msg) {
    console.log("收到candidate");
    var candidate = JSON.parse(msg.message);

    //添加IceCandidate
    pc.addIceCandidate(candidate)
        .then(function () {
            console.log("添加IceCandidate成功");
        })
        .catch(function (error) {
            console.log("添加IceCandidate失败:" + error);
        });


}

//设置onicecandidate回调函数,收集到Candidate信息时触发
function handleIceCandidate(event) {
    console.log("handleIceCandidate");
    if (event.candidate) {
        //发送candidate
        var jsonMsg = {
            "cmd": SIGNAL_TYPE_CANDIDATE,
            "roomId": roomId,
            "uid": localUserId,
            "remoteUid": remoteUserId,
            "message": JSON.stringify(event.candidate),
        };
        var message = JSON.stringify(jsonMsg);
        rtcEngine.sendMessage(message);

        console.log("发送candidate:" + message);
    }
    else {
        console.warn("结束candidate");
    }
}

//设置ontrack回调函数，接收到对端流时触发
function handleRemoteStreamAdd(event) {
    console.log("接收对端流");
    //设置对端流
    remoteStream = event.streams[0];
    remoteVideo.srcObject = remoteStream;
}

//加入房间，向服务器发送JSON消息
function doJoin(roomId) {
    var jsonMsg = {
        cmd: SIGNAL_TYPE_JOIN,
        roomId: roomId,
        uid: localUserId,
    };

    //发送JSON消息
    var message = JSON.stringify(jsonMsg);
    rtcEngine.sendMessage(message);

    console.log("发送JSON消息:" + message);
    isInRoom = true;
}

//离开房间，向服务器发送JSON消息
function doLeave() {
    isInRoom = false;
    console.log("is in Room " + isInRoom);
    var jsonMsg = {
        cmd: SIGNAL_TYPE_LEAVE,
        roomId: roomId,
        uid: localUserId,
    };

    var message = JSON.stringify(jsonMsg);
    rtcEngine.sendMessage(message);

    console.log("发送JSON消息:" + message);
    hangup();
}

//加入房间，给房间里面的人发送offer
function doOffer() {
    //创建RTCPeerConnection对象
    if (pc == null) {
        createPeerConnection();
    }
    pc.createOffer().then(createOfferAndSendMessage).catch(function (error) {
        console.log("创建offer失败");
    });
}

//加入房间，房间里面的人回复answer
function doAnswer() {
    pc.createAnswer().then(createAnswerAndSendMessage).catch(function (error) {
        console.log("创建answer失败");
    });
}

//创建和远端的连接
function createPeerConnection() {
    //stun服务器配置信息
    var defaultConfiguration = {
        bundlePolicy: "max-bundle",
        rtcpMuxPolicy: "require",
        iceTransportPolicy: "all", 
        iceServers: [
            {
                "urls": [
                    "turn:192.168.10.251:3478?transport=udp",
                    "turn:192.168.10.251:3478?transport=tcp" // 可以插入多个进行备选
                ],
                "username": "lh",
                "credential": "123456"
            },
            {
                "urls": [
                    "stun:192.168.10.251:3478"
                ]
            }
        ]
    };


    //创建RTCPeerConnection对象
    pc = new RTCPeerConnection(defaultConfiguration);
    // pc = new RTCPeerConnection(null);

    //设置回调函数
    pc.onicecandidate = handleIceCandidate; //设置IceCandidate回调函数
    pc.ontrack = handleRemoteStreamAdd; //设置远端流回调函数

    //遍历本地流，加入流中
    localStream.getTracks().forEach(function (track) {
        pc.addTrack(track, localStream);
    });

    console.log("创建RTCPeerConnection对象成功");
}

//发送offer并且发送sdp对象session，创建sdp
function createOfferAndSendMessage(session) {
    //设置本地sdp对象
    pc.setLocalDescription(session)
        .then(function () {
            //发送offer
            var jsonMsg = {
                "cmd": SIGNAL_TYPE_OFFER,
                "roomId": roomId,
                "uid": localUserId,
                "remoteUid": remoteUserId,
                "message": JSON.stringify(session),
            };
            var message = JSON.stringify(jsonMsg);
            rtcEngine.sendMessage(message);
            console.log("发送JSON消息:" + message);
        })
        .catch(function (error) {
            console.log("设置本地sdp对象失败");
        });
}

//发送answer并且发送sdp对象session，对比对端sdp后设置本地sdp
function createAnswerAndSendMessage(session) {
    pc.setLocalDescription(session)
        .then(function () {
            //发送answer
            var jsonMsg = {
                "cmd": SIGNAL_TYPE_ANSWER,
                "roomId": roomId,
                "uid": localUserId,
                "remoteUid": remoteUserId,
                "message": JSON.stringify(session),
            };
            var message = JSON.stringify(jsonMsg);
            rtcEngine.sendMessage(message);
            console.log("发送JSON消息:" + message);
        })
        .catch(function (error) {
            console.log("设置本地sdp对象失败");
        });
}

//挂断视频
function hangup() {
    //关闭本地流
    if (localStream != null) {
        localStream.getTracks().forEach(function (track) {
            track.stop();
        });
        localVideo.srcObject = null;
        localStream = null;
    }

    //关闭远端流
    if (remoteStream != null) {
        remoteStream.srcObject = null;
        remoteStream = null;
    }

    if (remoteVideo != null) {
        remoteVideo.srcObject = null;
    }

    if (pc != null) {
        pc.close(); //关闭RTCPeerConnection对象
        pc = null;
    }
}

//打开本地流并设置
function openLocalStream(stream) {
    console.log("打开本地流成功");

    //加入房间
    doJoin(roomId);

    //设置本地视频
    localVideo.srcObject = stream;
    localStream = stream;
}

//初始化本地流
function initLocalStream() {
    navigator.mediaDevices.getUserMedia({
        audio: true,
        video: true
    })
    .then(openLocalStream)
    .catch(function (e) {
        alert("getUserMedia() error: " + e.name);
    });
}

/*相当于main函数开始*/

//设置加入按钮点击事件
document.querySelector("#joinBtn").onclick = function () {

    if (isInRoom) {
        alert("请先离开当前房间");
        return;
    }
    roomId = document.getElementById("roomIdInput").value;
    if (roomId == "" || roomId == "请输入房间ID") {
        alert("请输入房间ID");
        return;
    }

    console.log("触发加入按钮点击事件,roomId = " + roomId);
    //初始化本地流
    initLocalStream();
};

//设置离开按钮点击事件
document.querySelector("#leaveBtn").onclick = function () {
    if (roomId == -1) {
        alert("请先加入房间");
        return;
    }

    console.log("触发离开按钮点击事件,roomId = " + roomId);

    if(rtcEngine != null){
        doLeave();
    }
}


//创建WebSocket连接
// rtcEngine = new RTCEngine("ws://192.168.217.128:9002");
rtcEngine = new RTCEngine("ws://192.168.10.251:9002");
// rtcEngine = new RTCEngine("wss://192.168.10.251:8098/ws");

rtcEngine.createWebSocket();


